using System.Collections.Generic;
using Gameplay.PVE.Utils;
using UnityEngine;
using Yoozoo.Libs;
using Yoozoo.Managers;
using Yoozoo.Gameplay.RTS;

namespace Gameplay.PVE.TurnBase
{
    public class SkillBase : IClass
    {
        void IClass.OnReset()
        {
            
        }

        protected enum ESkillState
        {
            None,
            MoveTo,
            Storage,
            Cast,
            Recover,
            MoveBack,
        }

        protected BattleUnit unit;
        protected ESkillState state;
        protected Vector3 targetPosition;
        protected Vector3 startPosition;
        protected BattleUnit targetUnit;
        protected List<BattleUnit> targetList = new List<BattleUnit>(); 
        public TbsSkillConfig config;
        protected float stateStartTime;

        private List<bool> castState = new List<bool>();
        private List<bool> effectState = new List<bool>();
        private bool hasRemoveUnitsFromCameraFocus = false;
        private float skillStartTime;
        private BattleUnit selectedTarget;

        private float skillCameraStartTime;
        private float moveSpeed;

        public void Init(BattleUnit unit,int id)
        {
            this.unit = unit;
            config = PveUtils.GetTbsSkillConfig(id);
        }

        public virtual void Start(BattleUnit target = null)
        {
            selectedTarget = target;
            SetTargets();
            if (targetList.Count == 0)
            {
                return;
            }
            unit.Data.IsCasting = true;
            unit.Data.IsInAction = true;
            startPosition = unit.Data.position;
            castState.Clear();
            for (int i = 0; i < config.castEvent.Count; i++)
            {
                castState.Add(false);
            }
            
            effectState.Clear();
            if (config.effectEvent != null)
            {
                for (int i = 0; i < config.effectEvent.Count; i++)
                {
                    effectState.Add(false);
                }
            }
            

            if (config.moveType != 0 && Vector3.Distance(targetPosition,unit.Data.position) >= 0.1f)
            {
                StartMoveTo();
            }
            else
            {
                StartStorage();
            }

            if (config.focus == 1)
            {
                hasRemoveUnitsFromCameraFocus = false;
                TurnBaseManager.Instance.AddTbsFocus(unit);
                for (int i = 0; i < targetList.Count; i++)
                {
                    TurnBaseManager.Instance.AddTbsFocus(targetList[i]);
                }
            }
           
            if (config.blackScreen == 1)
            {
                TurnBaseManager.Instance.AddBlackScreenSkill();
            }

            if (unit.Data.team == 2)
            {
                skillStartTime = TimeManager.logicTime;
                unit.Data.IsEnemyCastCd = true;
            }

            if (config.name != null && config.type == 0)
            {
                //PveFlyTextManager.Instance.ShowFlyText(config.name,unit.Data.position + new Vector3(0,0.5f,0),0.8f,0.3f,ETextColor.Yellow);
            }
        }
       
        private void SetTargets()
        {
            int targetTeam = 2 - unit.Data.team;
            if (config.targetType == 1)
            {
                targetTeam = unit.Data.team;
            }

            if (targetTeam == 2 && selectedTarget == null)
            {
                selectedTarget = TurnBaseManager.Instance.targetUnit;
            }
            targetList = GetTargetsByTeam(targetTeam,config.targetNum,config.targetSort);


            if (targetList.Count > 0)
            {
                targetUnit = targetList[0];
                targetPosition = targetUnit.Data.position;
                targetPosition.y = 0;
                if (config.moveType == 1)
                {
                    unit.Data.targetPosition = targetPosition + (unit.Data.position - targetPosition).normalized * config.attackRange;
                }
                else if (config.moveType == 2)
                {
                    unit.Data.targetPosition = unit.Data.position;
                    unit.Data.targetPosition = new Vector3(unit.Data.targetPosition.x,unit.Data.targetPosition.y,targetPosition.z);
                    if (Vector3.Distance(unit.Data.position, unit.Data.targetPosition) > 0.1f)
                    {
                        unit.Data.targetPosition += (unit.Data.position - unit.Data.targetPosition).normalized * 0.2f;
                    }

                }
                else
                {
                    unit.Data.targetPosition = unit.Data.position;
                }
                targetPosition = unit.Data.targetPosition;
            }
        }

        public virtual void Update()
        {
            if (unit.Data.isDead)
            {
                if (state != ESkillState.None)
                {
                    End();
                }
               
                return;
            }
            if (state == ESkillState.MoveTo)
            {
                MoveTo();
            }
            else if (state == ESkillState.Storage)
            {
                Storage();
            }
            else if (state == ESkillState.Cast)
            {
                Cast();
            }
            else if (state == ESkillState.Recover)
            {
                Recover();
            }
            else if (state == ESkillState.MoveBack)
            {
                MoveBack();
            }

            if (unit.Data.IsEnemyCastCd && TimeManager.logicTime - skillStartTime > unit.Data.enemyCastCd)
            {
                unit.Data.IsEnemyCastCd = false;
            }

            if (skillCameraStartTime != 0 && TimeManager.logicTime - skillCameraStartTime > config.cameraFrame / PveUtils.fps)
            {
                TurnBaseManager.Instance.HideSkillCamera(config.id);
                skillCameraStartTime = 0;
            }
        }

        protected virtual void StartMoveTo()
        {
            //Debug.Log("StartMoveTo");
            stateStartTime = TimeManager.logicTime;
            state = ESkillState.MoveTo;
            var distance = Vector3.Distance(unit.Data.position, unit.Data.targetPosition);
            float moveToTime = 0.3f;
            if (config.moveToFrame != 0)
            {
                moveToTime = (config.moveToFrame - config.moveToDelayFrame) / PveUtils.fps / config.moveToSpeed;
            }
            moveSpeed = distance / moveToTime;
            float speed = 0;//Mathf.Sqrt(0.5f * 2 * GravityComponent.gravity);
            unit.Data.velocity = new Vector3(0,speed,0);
        }

        protected virtual void StartStorage()
        {
            //Debug.Log("StartStorage");
            state = ESkillState.Storage;
            stateStartTime = TimeManager.logicTime;
        }

        protected virtual void StartCast()
        {
            //Debug.Log("StartCast");
            if (config.cameraFrame != 0 && unit.Data.team == 0)
            {
                skillCameraStartTime = TimeManager.logicTime;
                TurnBaseManager.Instance.ShowSkillCamera(unit.gameObject.transform,config.id);
            }
            state = ESkillState.Cast;
            stateStartTime = TimeManager.logicTime;
        }

        protected virtual void StartRecover()
        {
            //Debug.Log("StartRecover");
            state = ESkillState.Recover;
            stateStartTime = TimeManager.logicTime;
        }
        
        protected virtual void StartMoveBack()
        {
            //Debug.Log("StartMoveBack");
            state = ESkillState.MoveBack;
            stateStartTime = TimeManager.logicTime;
            var distance = Vector3.Distance(unit.Data.position, startPosition);
            float moveToTime = 0.3f;
            if (config.moveBackFrame != 0)
            {
                moveToTime = (config.moveBackFrame - config.moveBackStayFrame - config.moveBackDelayFrame) / PveUtils.fps / config.moveBackSpeed;
            }
            moveSpeed = distance / moveToTime;
            float speed = 0;//Mathf.Sqrt(0.5f * 2 * GravityComponent.gravity);
            unit.Data.velocity = new Vector3(0,speed,0);
        }
        
        protected virtual void MoveTo()
        {
            //Debug.Log("MoveTo");
            if (TimeManager.logicTime - stateStartTime < config.moveToDelayFrame / PveUtils.fps / config.moveToSpeed)
            {
                return;
            }
            var diff = targetPosition - unit.Data.position;
            var speed = moveSpeed * TimeManager.GameDeltaTime;
            var sqrMag = diff.sqrMagnitude;
            //if (sqrMag <= config.attackRange * config.attackRange || sqrMag <= speed * speed)
            if (sqrMag <= speed * speed)
            {
                StartStorage();
            }
            else
            {
                unit.Data.SetPosition(unit.Data.position + diff.normalized * speed);
                diff.y = 0;
                unit.Data.SetForward(diff);
            }
        }

        protected virtual void Storage()
        {
            if (TimeManager.logicTime - stateStartTime >= config.storageFrame / PveUtils.fps)
            {
                StartCast();
            }
        }

        protected virtual void Cast()
        {
            for (int i = 0; i < config.castEvent.Count; i++)
            {
                if (!castState[i] && TimeManager.logicTime - stateStartTime > config.castEvent[i].x / PveUtils.fps)
                {
                    CastEvent((int)config.castEvent[i].y);
                    castState[i] = true;
                }
            }

            for (int i = 0; i < effectState.Count; i++)
            {
                if (!effectState[i] && TimeManager.logicTime - stateStartTime > config.effectEvent[i].x / PveUtils.fps)
                {
                    EffectEvent((int) config.effectEvent[i].y);
                    effectState[i] = true;
                }
            }
            if (TimeManager.logicTime - stateStartTime >= config.castFrame / PveUtils.fps)
            {
                StartRecover();
            }
        }

        protected virtual void Recover()
        {
            if (TimeManager.logicTime - stateStartTime >= config.recoverFrame / PveUtils.fps)
            {
                if (config.moveType != 0 && Vector3.Distance(startPosition,unit.Data.position) >= 0.1f)
                {
                    StartMoveBack();
                    unit.Data.targetPosition = startPosition;
                }
                else
                {
                    End();
                }
                RemoveUnitsFromCameraFocus();
            }
        }

        protected virtual void MoveBack()
        {
            if (TimeManager.logicTime - stateStartTime < config.moveBackDelayFrame / PveUtils.fps / config.moveToSpeed)
            {
                return;
            }
            var diff = startPosition - unit.Data.position;
            var speed = moveSpeed * TimeManager.GameDeltaTime;
            var sqrMag = diff.sqrMagnitude;
            if (sqrMag <= speed * speed)
            {
                if (TimeManager.logicTime - stateStartTime > config.moveBackFrame / PveUtils.fps)
                {
                    End();
                }
            }
            else
            {
                unit.Data.SetPosition(unit.Data.position + diff.normalized * speed);
                diff.y = 0;
                //unit.Data.SetForward(diff);
            }
        }

        protected virtual void End()
        {
            state = ESkillState.None;
            unit.Data.SetForward(unit.Data.birthForward);
            RemoveUnitsFromCameraFocus();
        }

        private void EffectEvent(int effectId)
        {
            if (targetUnit != null)
            {
                PveEffectManager.Instance.PlayEffect(effectId,targetUnit.Data.position,Vector3.forward);
            }
            
        }

        private void CastEvent(int elementId)
        {
            Vector3 offset = PveUtils.globalRatio * new Vector3(0.15f, 1.5f, 1.2f);
            float angle = PveUtils.GetAngle(Vector3.forward, unit.Data.forward);
            offset = Quaternion.AngleAxis(angle, Vector3.up) * offset;
            Vector3 position = unit.Data.position + offset +
                               Quaternion.AngleAxis(angle, Vector3.up) * new Vector3(0, -0.1f, -0.3f);
            PveEffectManager.Instance.PlayEffect(2,position,unit.Data.forward,0.3f);
            var arg = ClassManager.Get<AddElementArg>();
            arg.source = unit;
            arg.elementId = elementId;
            if (unit.Data.team == 0)
            {
                TurnBaseManager.Instance.TeamUltraCurrentValue += 25;
            }

            var config = PveUtils.GetTbsSkillElementConfig(elementId);
            
            for (int i = 0; i < targetList.Count; i++)
            {
                var target = targetList[i];
                target.Transmit(ETransmitType.AddElement,arg);
                /*if (config.velocity != Vector3.zero)
                {
                    var hitArg = ClassManager.Get<HitFloatArg>();
                    hitArg.velocity = config.velocity;
                    hitArg.source = unit;
                    target.Transmit(ETransmitType.HitFloat,hitArg);
                }*/
            }
        }

        protected void RemoveUnitsFromCameraFocus()
        {
            if (config.focus == 1)
            {
                if (!hasRemoveUnitsFromCameraFocus)
                {
                    TurnBaseManager.Instance.RemoveTbsFocus(unit);
                    for (int i = 0; i < targetList.Count; i++)
                    {
                        TurnBaseManager.Instance.RemoveTbsFocus(targetList[i]);
                    }

                    if (config.blackScreen == 1)
                    {
                        TurnBaseManager.Instance.RemoveBlackScreenSkill();
                    }
                
                    hasRemoveUnitsFromCameraFocus = true;
                }
            }
        }
        
        public bool IsInAction()
        {
            return state != ESkillState.None;
        }

        public bool IsCasting()
        {
            return (state == ESkillState.MoveTo || state == ESkillState.Cast || state == ESkillState.Storage);
        }

        /// <summary>
        /// 随机
        /// </summary>
        /// <param name="candidates"></param>
        /// <returns></returns>
        private List<BattleUnit> GetRandomTargets(List<BattleUnit> candidates,int num)
        {
            var targetList = new List<BattleUnit>();
            for (int i = 0; i < candidates.Count; i++)
            {
                targetList.Add(candidates[i]);
            }
            //BattleUtils.Shuffle(ref targetList);
            targetList.Sort(DistanceSort);
            if (selectedTarget != null)//优先选择玩家选中的目标
            {
                for (int i = 0; i < targetList.Count; i++)
                {
                    if (targetList[i] == selectedTarget)
                    {
                        targetList.RemoveAt(i);
                        targetList.Insert(0,selectedTarget);
                    }
                }
            }
            int removeNum = targetList.Count - num;
            for (int i = 0; i < removeNum; i++)
            {
                targetList.RemoveAt(targetList.Count - 1);
            }

            return targetList;
        }
        
        /// <summary>
        /// 纵列
        /// </summary>
        /// <param name="candidates"></param>
        /// <returns></returns>
        private List<BattleUnit> GetColumnTargets(List<BattleUnit> candidates)
        {
            var targetList = new List<BattleUnit>();
            var targetColumn = selectedTarget?.Data.column ?? unit.Data.column;
            //先找目标列数
            for (int i = 0; i < candidates.Count; i++)
            {
                if (candidates[i].Data.column == targetColumn)
                {
                    targetList.Add(candidates[i]);
                }
            }
            
            //如果目标数量为0
            if (targetList.Count == 0)
            {
                targetColumn = candidates[Random.Range(0, candidates.Count)].Data.column;
                for (int i = 0; i < candidates.Count; i++)
                {
                    if (candidates[i].Data.column == targetColumn)
                    {
                        targetList.Add(candidates[i]);
                    }
                }
            }
            return targetList;
        }
        
        /// <summary>
        /// 根据特定排序，取前n个
        /// </summary>
        /// <returns></returns>
        private List<BattleUnit> GetSortTargets(List<BattleUnit> candidates,int num, int sortType)
        {
            var targetList = new List<BattleUnit>();
            for (int i = 0; i < candidates.Count; i++)
            {
                targetList.Add(candidates[i]);
            }
            if (sortType == 1)//血量最低
            {
                targetList.Sort(HpLessSort);
            }
            else if (sortType == 2)//血量最高
            {
                targetList.Sort(HpMoreSort);
            }

            int removeNum = targetList.Count - num;
            for (int i = 0; i < removeNum; i++)
            {
                targetList.RemoveAt(targetList.Count - 1);
            }
            return targetList;
        }

        private List<BattleUnit> GetRowTargets(List<BattleUnit> candidates, int row)
        {
            var targetList = new List<BattleUnit>();
            for (int i = 0; i < candidates.Count; i++)
            {
                if (candidates[i].Data.row == row)
                {
                    targetList.Add(candidates[i]);
                }
            }
            return targetList;
        }
        
        private List<BattleUnit> GetTargetsByTeam(int team,int num,int targetSort)
        {
            var list = TurnBaseManager.Instance.GetAllUnitByTeam(team);
            if (targetSort == 0)
            {
                return GetRandomTargets(list,num);
            }
            else if (targetSort == 1 || targetSort == 2)
            {
                return GetSortTargets(list,num,targetSort);
            }
            else if (targetSort == 3)
            {
                return GetColumnTargets(list);
            }
            else if (targetSort == 4)
            {
                return GetRowTargets(list,0);
            }
            else if (targetSort == 5)
            {
                return GetRowTargets(list,1);
            }
            return new List<BattleUnit>();
        }

        private int DistanceSort(BattleUnit a,BattleUnit b)
        {
            float dist1 = (unit.Data.position - a.Data.position).sqrMagnitude;
            float dist2 = (unit.Data.position - b.Data.position).sqrMagnitude;
            return dist1.CompareTo(dist2);
        }
        
        private int HpLessSort(BattleUnit a,BattleUnit b)
        {
            return a.Data.CurrentHp.CompareTo(b.Data.CurrentHp);
        }

        private int HpMoreSort(BattleUnit a, BattleUnit b)
        {
            return b.Data.CurrentHp.CompareTo(a.Data.CurrentHp);
        }

        private int SelfSort(BattleUnit a, BattleUnit b)
        {
            if (b == unit)
            {
                return 1;
            }

            return -1;
        }
    }
}